package service

import (
	"context"
	"errors"
	"fmt"
	"time"

	"gitee.com/daonna/collab-manage-system/ent"
	"gitee.com/daonna/collab-manage-system/ent/conversation"
	"gitee.com/daonna/collab-manage-system/ent/conversationmember"
	"gitee.com/daonna/collab-manage-system/ent/message"
	"gitee.com/daonna/collab-manage-system/repository/db"
)

// MessageInfo 消息信息结构体
type MessageInfo struct {
	ID             int64     `json:"id"`
	ConvID         int64     `json:"conversation_id"`
	SenderID       int64     `json:"sender_id"`
	SenderName     string    `json:"sender_name"`
	SenderAvatar   string    `json:"sender_avatar"`
	Content        string    `json:"content"`
	ContentType    string    `json:"content_type"`
	FileURL        string    `json:"file_url,omitempty"`
	FileName       string    `json:"file_name,omitempty"`
	FileSize       int64     `json:"file_size,omitempty"`
	IsEdited       bool      `json:"is_edited"`
	IsDeleted      bool      `json:"is_deleted"`
	ReplyToID      int64     `json:"reply_to_id,omitempty"`
	ReplyToContent string    `json:"reply_to_content,omitempty"`
	CreatedAt      time.Time `json:"created_at"`
	UpdatedAt      time.Time `json:"updated_at"`
}

// SendMessage 发送消息
func SendMessage(
	ctx context.Context,
	conversationID int64,
	senderID uint,
	content string,
	contentType string,
	fileURL string,
	fileName string,
	fileSize int64,
	replyToID int64,
) (int64, error) {
	client := db.GetDBClient()

	// 开始事务
	tx, err := client.Group().Tx(ctx)
	if err != nil {
		return 0, fmt.Errorf("开始事务失败: %w", err)
	}
	defer func() {
		if v := recover(); v != nil {
			tx.Rollback()
			panic(v)
		}
	}()

	// 检查会话是否存在
	conv, err := client.Conversation().Conversation.Get(ctx, conversationID)
	if err != nil {
		tx.Rollback()
		if ent.IsNotFound(err) {
			return 0, errors.New("会话不存在")
		}
		return 0, fmt.Errorf("查询会话失败: %w", err)
	}

	// 检查发送者是否是会话成员
	isMember, err := client.ConversationMember().ConversationMember.
		Query().
		WithConversation().
		Where(
			conversationmember.ConversationID(conversationID),
			conversationmember.UserID(int64(senderID)),
		).
		Exist(ctx)

	if err != nil {
		tx.Rollback()
		return 0, fmt.Errorf("检查发送者权限失败: %w", err)
	}

	if !isMember {
		tx.Rollback()
		return 0, errors.New("您不是该会话的成员")
	}

	// 创建消息构建器
	messageBuilder := client.Message().Message.
		Create().
		SetConversationID(conversationID).
		SetSenderID(int64(senderID)).
		SetContent(content).
		SetContentType(message.ContentType(contentType))

	// 如果提供了文件信息，设置文件相关字段
	if fileURL != "" {
		messageBuilder = messageBuilder.
			SetFileURL(fileURL).
			SetFileName(fileName).
			SetFileSize(fileSize)
	}

	// 如果是回复消息，检查被回复的消息是否存在
	if replyToID > 0 {
		replyExists, err := client.Message().Message.
			Query().
			Where(
				message.ID(replyToID),
				message.ConversationID(conversationID),
			).
			Exist(ctx)

		if err != nil {
			tx.Rollback()
			return 0, fmt.Errorf("检查回复消息失败: %w", err)
		}

		if !replyExists {
			tx.Rollback()
			return 0, errors.New("被回复的消息不存在")
		}
		
		// 只有回复消息ID有效时才设置 ReplyToID
		messageBuilder = messageBuilder.SetReplyToID(replyToID)
	}

	// 保存消息
	msg, err := messageBuilder.Save(ctx)

	if err != nil {
		tx.Rollback()
		return 0, fmt.Errorf("创建消息失败: %w", err)
	}

	// 更新会话的最后消息时间
	_, err = client.Conversation().Conversation.
		UpdateOne(conv).
		SetLastMessageAt(time.Now()).
		Save(ctx)

	if err != nil {
		tx.Rollback()
		return 0, fmt.Errorf("更新会话最后消息时间失败: %w", err)
	}

	// 提交事务
	if err := tx.Commit(); err != nil {
		return 0, fmt.Errorf("提交事务失败: %w", err)
	}

	return msg.ID, nil
}

// ListMessages 获取会话中的消息
func ListMessages(
	ctx context.Context,
	conversationID int64,
	userID uint,
	limit int,
	offset int,
) ([]*MessageInfo, error) {
	client := db.GetDBClient()

	// 检查用户是否是会话成员
	isMember, err := client.ConversationMember().ConversationMember.
		Query().
		Where(
			conversationmember.ConversationID(conversationID),
			conversationmember.UserID(int64(userID)),
		).
		Exist(ctx)

	if err != nil {
		return nil, fmt.Errorf("检查用户权限失败: %w", err)
	}

	if !isMember {
		return nil, errors.New("您不是该会话的成员")
	}

	// 查询消息列表
	messages, err := client.Message().Message.
		Query().
		Where(message.ConversationID(conversationID)).
		Order(ent.Desc(message.FieldCreatedAt)).
		Limit(limit).
		Offset(offset).
		WithSender().
		WithReplyTo().
		All(ctx)

	if err != nil {
		return nil, fmt.Errorf("查询消息失败: %w", err)
	}

	// 构建返回结果
	result := make([]*MessageInfo, 0, len(messages))
	for _, msg := range messages {
		var senderName, senderAvatar string
		if msg.Edges.Sender != nil {
			senderName = msg.Edges.Sender.DisplayName
			senderAvatar = msg.Edges.Sender.AvatarURL
		}

		var replyToContent string
		if msg.Edges.ReplyTo != nil {
			replyToContent = msg.Edges.ReplyTo.Content
		}

		messageInfo := &MessageInfo{
			ID:             msg.ID,
			ConvID:         msg.ConversationID,
			SenderID:       msg.SenderID,
			SenderName:     senderName,
			SenderAvatar:   senderAvatar,
			Content:        msg.Content,
			ContentType:    msg.ContentType.String(),
			FileURL:        msg.FileURL,
			FileName:       msg.FileName,
			FileSize:       msg.FileSize,
			IsEdited:       msg.IsEdited,
			IsDeleted:      msg.IsDeleted,
			ReplyToID:      msg.ReplyToID,
			ReplyToContent: replyToContent,
			CreatedAt:      msg.CreatedAt,
			UpdatedAt:      msg.UpdatedAt,
		}

		result = append(result, messageInfo)
	}

	return result, nil
}

// UpdateMessage 更新消息（编辑）
func UpdateMessage(
	ctx context.Context,
	messageID int64,
	userID uint,
	content string,
) error {
	client := db.GetDBClient()

	// 开始事务
	tx, err := client.Group().Tx(ctx)
	if err != nil {
		return fmt.Errorf("开始事务失败: %w", err)
	}
	defer func() {
		if v := recover(); v != nil {
			tx.Rollback()
			panic(v)
		}
	}()

	// 获取消息信息
	msg, err := client.Message().Message.Get(ctx, messageID)
	if err != nil {
		tx.Rollback()
		if ent.IsNotFound(err) {
			return errors.New("消息不存在")
		}
		return fmt.Errorf("查询消息失败: %w", err)
	}

	// 检查是否是消息发送者
	if msg.SenderID != int64(userID) {
		tx.Rollback()
		return errors.New("只能编辑自己发送的消息")
	}

	// 不能编辑已删除的消息
	if msg.IsDeleted {
		tx.Rollback()
		return errors.New("不能编辑已删除的消息")
	}

	// 更新消息内容
	_, err = client.Message().Message.
		UpdateOne(msg).
		SetContent(content).
		SetIsEdited(true).
		Save(ctx)

	if err != nil {
		tx.Rollback()
		return fmt.Errorf("更新消息失败: %w", err)
	}

	// 提交事务
	if err := tx.Commit(); err != nil {
		return fmt.Errorf("提交事务失败: %w", err)
	}

	return nil
}

// DeleteMessage 删除消息
func DeleteMessage(
	ctx context.Context,
	messageID int64,
	userID uint,
) error {
	client := db.GetDBClient()

	// 开始事务
	tx, err := client.Group().Tx(ctx)
	if err != nil {
		return fmt.Errorf("开始事务失败: %w", err)
	}
	defer func() {
		if v := recover(); v != nil {
			tx.Rollback()
			panic(v)
		}
	}()

	// 获取消息信息
	msg, err := client.Message().Message.Get(ctx, messageID)
	if err != nil {
		tx.Rollback()
		if ent.IsNotFound(err) {
			return errors.New("消息不存在")
		}
		return fmt.Errorf("查询消息失败: %w", err)
	}

	// 检查是否有权限删除该消息
	// 只能删除自己的消息，或者是管理员/群主删除群聊中的消息
	if msg.SenderID != int64(userID) {
		// 获取会话信息
		conv, err := client.Conversation().Conversation.Get(ctx, msg.ConversationID)
		if err != nil {
			tx.Rollback()
			return fmt.Errorf("获取会话信息失败: %w", err)
		}

		// 如果是群聊，检查是否是管理员或群主
		if conv.Type == conversation.TypeGroup {
			isAdmin, err := client.ConversationMember().ConversationMember.
				Query().
				Where(
					conversationmember.ConversationID(msg.ConversationID),
					conversationmember.UserID(int64(userID)),
					conversationmember.RoleIn(conversationmember.RoleOwner, conversationmember.RoleAdmin),
				).
				Exist(ctx)

			if err != nil {
				tx.Rollback()
				return fmt.Errorf("检查用户权限失败: %w", err)
			}

			if !isAdmin {
				tx.Rollback()
				return errors.New("您没有权限删除他人的消息")
			}
		} else {
			// 私聊中不能删除他人消息
			tx.Rollback()
			return errors.New("只能删除自己发送的消息")
		}
	}

	// 标记消息为已删除（软删除）
	_, err = client.Message().Message.
		UpdateOne(msg).
		SetIsDeleted(true).
		SetContent("[此消息已删除]").
		Save(ctx)

	if err != nil {
		tx.Rollback()
		return fmt.Errorf("删除消息失败: %w", err)
	}

	// 提交事务
	if err := tx.Commit(); err != nil {
		return fmt.Errorf("提交事务失败: %w", err)
	}

	return nil
}
